using System;
using System.Collections.Generic;
using System.Threading;
using CommonTypes.Server.Operations;

namespace Server.Model
{
    public class ServerData
    {
        private readonly String _serverId;
        private readonly bool _isGUIPresent;
        private readonly SortedDictionary<String, User> _usersList;
        private readonly bool _standalone;
        private readonly ServersInformation _serversInformation;
        private readonly PingData _pingData;
        private readonly AutoResetEvent _terminateServer;
        private readonly AutoResetEvent _isTerminated;
        private bool _performingSync;
        private readonly SortedDictionary<long, Operation> _opList = new SortedDictionary<long, Operation>( );
        private bool _isConnected;
        public static readonly int NUMBER_OF_PING_TRIES = 5;

        private ServerState _state;
        private long _ticketNumber;
        private long _serverLogicalClock;

        #region Locks

        private readonly Object _ticketNumberLock = new Object( );
        private readonly Object _serverLogicalClockLock = new Object( );
        private readonly Object _dictionaryLock = new Object( );
        private readonly Object _syncLock = new Object( );
        private readonly ReaderWriterLockSlim _stateLock = new ReaderWriterLockSlim( );
        private readonly ReaderWriterLockSlim _terminateLock = new ReaderWriterLockSlim( );

        #endregion Locks

        public ServerData( String serverId, bool standalone, bool gui )
        {
            _serverId = serverId;
            _serversInformation = new ServersInformation( );
            _terminateServer = new AutoResetEvent( false );
            _isTerminated = new AutoResetEvent( false );
            _pingData = new PingData( );

            _usersList = new SortedDictionary<String, User>( );
            _ticketNumber = 0;
            _state = ServerState.ADDREMOVE;
            _serverLogicalClock = 0;
            _isGUIPresent = gui;
            _standalone = standalone;
            _syncLock = false;

            IsConnected = true;
        }

        public ServersInformation ServersInformation
        {
            get
            {
                return _serversInformation;
            }
        }

        public PingData PingInformation
        {
            get
            {
                return _pingData;
            }
        }

        public SortedDictionary<long, Operation> Operations
        {
            get
            {
                SortedDictionary<long, Operation> ops;
                lock( _dictionaryLock )
                    ops = _opList;
                return ops;
            }
        }

        public EventWaitHandle IsTerminated
        {
            get
            {
                AutoResetEvent tmp;
                lock( _terminateLock )
                    tmp = _isTerminated;
                return tmp;
            }
        }

        public bool Standalone
        {
            get
            {
                return _standalone;
            }
        }

        public bool PerformingSync
        {
            get
            {
                bool tmp;
                lock( _syncLock )
                    tmp = _performingSync;
                return tmp;
            }
            set
            {
                lock( _syncLock )
                    _performingSync = value;
            }
        }

        public String ServerId
        {
            get
            {
                return _serverId;
            }
        }

        public bool IsGUIPresent
        {
            get
            {
                return _isGUIPresent;
            }
        }

        public bool IsConnected
        {
            get
            {
                return _isConnected;
            }
            set
            {
                if( false == value )
                    _state = ServerState.DISCONNECTED;
                _isConnected = value;
            }
        }

        public SortedDictionary<String, User> UsersList
        {
            get
            {
                SortedDictionary<String, User> ops;
                lock( _dictionaryLock )
                    ops = _usersList;
                return ops;
            }
        }

        public AutoResetEvent Terminate
        {
            get
            {
                AutoResetEvent tmp;
                lock( _terminateLock )
                    tmp = _terminateServer;
                return tmp;
            }
        }

        public long TicketNumber
        {
            get
            {
                long ret;
                lock( _ticketNumberLock )
                    ret = _ticketNumber;
                return ret;
            }

            set
            {
                lock( _ticketNumberLock )
                    _ticketNumber = value;
            }
        }

        public ServerState State
        {
            get
            {
                ServerState ret;
                _stateLock.EnterReadLock( );
                ret = _state;
                _stateLock.ExitReadLock( );
                return ret;
            }

            set
            {
                _stateLock.EnterWriteLock( );
                _state = value;
                _stateLock.ExitWriteLock( );
            }
        }

        public long ServerLogicalClock
        {
            get
            {
                long ret;
                lock( _serverLogicalClockLock )
                    ret = _serverLogicalClock;
                return ret;
            }

            set
            {
                lock( _serverLogicalClockLock )
                    _serverLogicalClock = value;
            }
        }
    }
}